/**
 * @description user 服务层
 * @author LI
 */

const {
  User,
  GoodsInfo,
  Product,
  DecoratItem,
  GoodsPhoto,
  DecoratItemInfo,
  Account,
  AccessRecord
} = require('../db/model/index')
const axios = require('axios')
const querystring = require('querystring')
const Sequelize = require('sequelize')
const Op = require('sequelize').Op
const { formatMoreTime } = require('../utils/dateTime')
const { differenceInHours } = require('date-fns')
const BigNumber = require('bignumber.js')
const {
  setPhoneCode,
  getPhoneCode,
  setPhoneCodeExpired
} = require('../cache/phoneCode')
const {
  SMS_BASE_URL,
  API_ID,
  API_KEY
} = require('../conf/secretKeys')

/**
 * 创建用户信息
 * @param {string} userName 姓名
 * @param {string} phone 手机号
 * @param {number} area 面积
 * @param {string} address 地址
 * @param {string} remark 备注/要求
 */
async function createUser({ userName, phone, area, address, remark }) {
  if (!area) {
    area = 0
  }
  // 接下来数据库操作，进行增删改查
  const result = await User.create({
    userName,
    phone,
    area,
    address,
    remark
  })

  return result
}

/**
 * 发送短信提示
 * @param {string} phone 手机号
 */
async function sendSMS(phone) {
  console.log('----  +  '+phone)
  const content = `提交信息的手机号为：${phone}，请及时联系沟通装修信息！`
  const dataSMS = {
    account: API_ID,
    password: API_KEY,
    // mobile: 13046653108,
    mobile: 15136935216,
    content,
    format: 'json'
  }
  // util.inspect(result)
  const { data } = await axios.post(SMS_BASE_URL, querystring.stringify(dataSMS))
  // 设置一个长期验证码失效时间
  if (data.code !== 2) {
    throw new Error(data.msg)
  }
  console.log('---- '+JSON.stringify(data))
  
  return data.msg
}

/**
 * 根据分类名称获取产品列表和装修项目列表，算出他们每个的总额
 * @param {string} typeName 分类名称，通过名称查询全部商品
 * @param {number} page 第几页
 * @param {number} limit 条数
 */
async function getGoodListByTypeName({ typeName, page = 1, limit = 8 }) {
  // 接下来数据库操作，进行增删改查
  let result = await GoodsInfo.findAndCountAll({
    limit: limit, // 每页多少条
    offset: limit * (page - 1), // 跳过多少条
    where: {
      goodType: {
        [Op.like]: '%' + typeName + '%'
      }
    },
    order: [['goodSort', 'DESC']],
    include: [
      {
        model: Product,
        attributes: ['productNumber', 'productPrice', 'id', 'productSn'],
      },
      {
        model: DecoratItemInfo,
        attributes: ['itemNumber', 'decoratItemId', 'itemPrice'],

      }
    ]
  })

  // 过滤信息返回总金额
  result.rows.map(item => {

    // 格式化时间 多个
    item.dataValues = formatMoreTime(item.dataValues)

    if (item.dataValues.decoratItemInfos instanceof Array) {
      item.dataValues.decoratItemSum = 0
      item.decoratItemInfos.map(j => {
        item.dataValues.decoratItemSum += j.itemNumber * j.itemPrice
      })
      item.dataValues.decoratItemSum = Math.floor(item.dataValues.decoratItemSum * 100) / 100
    }

    if (item.dataValues.products instanceof Array) {
      let prod = item.dataValues.products
      prod = prod.reverse().filter((item1, index) => {
        let _index = prod.findIndex((_item) => {
          return item1.productSn === _item.productSn
        })
        return index === _index
      })
      item.dataValues.productSum = 0
      prod.map(i => {
        item.dataValues.productSum += i.productNumber * i.productPrice
      })
      item.dataValues.productSum = Math.floor(item.dataValues.productSum * 100) / 100
    }

  })

  return result
}

/**
 * 根据商品 id 获取商品详细信息，包括产品装修列表
 * @param {number} id 商品 id
 */
async function getGoodsInfoListById(id) {
  let result = await GoodsInfo.findAll({
    where: { id },
    include: [
      { model: Product },
      { model: DecoratItem },
      { model: GoodsPhoto },
    ]
  })

  return result
}

/**
 * 获取商品图片信息列表
 * @param {number} id 商品 id 用来获取商品图片列表
 */
async function getGoodsPhotoInfoById(id) {
  let result = await GoodsPhoto.findAndCountAll({
    where: { goodsInfoId: id }
  })

  return result
}

/**
 * 获取商品产品信息列表
 * @param {number} id 商品 id 用来获取商品产品列表
 */
async function getGoodsProductsInfoById(id) {
  let result = await Product.findAndCountAll({
    where: { goodsInfoId: id }
  })

  return result
}

/**
 * 获取商品装修信息列表
 * @param {number} id 商品 id 用来获取商品装修列表
 */
async function getGoodsDecoratitemsInfoById(id) {
  // let result = await DecoratItem.findAndCountAll({
  //   where: { goodsInfoId: id }
  // })

  const result = await DecoratItemInfo.findAndCountAll({
    where: { goodsInfoId: id },
    include: [
      {
        model: DecoratItem,
        where: { id: Sequelize.col('decoratItemInfo.decoratItemId') }
      }
    ]
  })

  result.rows.map(item => {
    // 格式化时间 多个
    item.dataValues = formatMoreTime(item.dataValues)
    item.dataValues.itemSn = item.dataValues.decoratItem.itemSn
    item.dataValues.itemName = item.dataValues.decoratItem.itemName
    item.dataValues.itemUnit = item.dataValues.decoratItem.itemUnit
    item.dataValues.itemRemark = item.dataValues.decoratItem.itemRemark
    delete item.dataValues.decoratItem
  })

  return result
}

/**
 * 通过链接判断是否为账号表里面的店铺链接
 * @param companyAddress 用户点击的链接
 */
async function linkAccount(companyAddress) {
  const result = await Account.findOne({
    where: {
      typecode: 2,
      companyAddress: {
        [Op.like]: '%' + companyAddress + '%'
      }
    },
  })

  return result
}

/**
 * 判断 ip 距离上个时间点是否超过 24 小时
 * @param {number} linkUserId 链接用户 id
 * @param {number} deductionPrice 链接用户的扣费价格
 * @param {string} accessIp 用户客户端 ip
 */
async function timeOutIP({ linkUserId, deductionPrice, accessIp }) {
  let result1 = await AccessRecord.findOne({
    where: {
      accessIp: {
        [Op.like]: '%' + accessIp + '%'
      }
    },
    order: [['createdAt', 'DESC']],
  })
  let hoursDate = 25
  if (result1) {
    let createdAt = result1.createdAt
    let date = new Date()
    // 判断相差几个小时
    hoursDate = differenceInHours(date, createdAt)
  }
  if (hoursDate <= 24) {
    return false
  } else {
    const result = await AccessRecord.create({
      linkUserId,
      deductionPrice,
      accessIp,
    })
    return result
  }
}

/**
 * 通过链接进行店铺相应的扣款
 * @param {number} linkUserId 用户点击的链接
 * @param {number} deductionPrice 广告价格一次扣款多少钱
 * @param {number} balance 用户余额
 */
async function linkUserDeductionByLink(linkUserId, deductionPrice, balance) {
  let balanceBig = new BigNumber(balance).minus(deductionPrice)
  const updateData = {
    balance: balanceBig
  }
  const result = await Account.update(updateData, {
    where: { id: linkUserId }
  })

  return result
}

/**
 * 获取短信验证码
 * @param phone 手机号账号
 */
async function getSMSCodeByPhone(phone) {
  const code = Math.floor(Math.random() * (9999 - 1000)) + 1000
  // 获取短期失效时间 60s isCode 为 数字，证明有值，已经存在，
  const isCode = await getPhoneCode(phone, String(code))
  if (isCode) {
    throw new Error('验证码已存在，请等待')
  }
  const content = `您的验证码是：${code}，请不要把验证码泄露给其他人，如非本人操作，可不用理会！`
  const data = {
    account: API_ID,
    password: API_KEY,
    mobile: phone,
    content,
    format: 'json'
  }
  // util.inspect(result)
  const result = await axios.post(SMS_BASE_URL, querystring.stringify(data)).then(response => {
    const resData = response.data
    // 设置一个长期验证码失效时间
    setPhoneCodeExpired(phone, String(code))
    // 设置一个短期验证码失效时间
    setPhoneCode(phone, String(code))
    if (resData.code !== 2) {
      throw new Error(resData.msg)
    }
    return resData
  }).catch(error => {
    console.error(error)
    throw new Error(error)
  })

  return result.msg
}

/**
 * 通过 phone 重置密码
 * @param {number} account 手机账号
 * @param {string} pwd 密码
 */
async function updateUserPwdByAccount({ account, pwd }) {
  const result = await Account.update({ pwd }, {
    where: {
      account
    }
  })
  
  return result[0] > 0
}

/**
 * 获取 qq 用户账号信息 openId
 * @param {string} code qq code码
 */
async function getQQUserInfoByCode(code) {
  // util.inspect(result)
  const data = {
    appid: APPID,
    secret: SECRET,
    js_code: code,
    grant_type: 'authorization_code'
  }
  const result = await axios.get(QQ_BASE_URL, {
    params: data
  }).then(res => {
    return res.data
  }).catch(error => {
    console.error(error)
    throw new Error(error)
  })
  
  return result
}

module.exports = {
  createUser,
  getGoodListByTypeName,
  getGoodsInfoListById,
  getGoodsPhotoInfoById,
  getGoodsProductsInfoById,
  getGoodsDecoratitemsInfoById,
  linkUserDeductionByLink,
  linkAccount,
  timeOutIP,
  getSMSCodeByPhone,
  updateUserPwdByAccount,
  getQQUserInfoByCode,
  sendSMS
}
